﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Text;

using GameServer.Networking.Packets;
using GameServer.Virtual_Objects.User;
using GameServer.Managers;
using GameServer.Networking;

namespace GameServer
{
    class Program
    {
        private static Thread _ServerThread = null;
        private static Thread _CommandThread = null;
        private static Thread _CouponThread = null;
        private static bool _Running = false;
        public static bool Running { get { return _Running; } }
        public static int BootTime;
        public static bool ESL = false;
        public static bool isEvent = false;
        public static int EventTime = -1;
        public static int EXPEvent = -1;
        public static int DinarEvent = -1;

        ~Program()
        {
            GC.Collect();
        }

        static void Main(string[] args)
        {
	        Boot();
        }
        
        public static String hashMD5(String Input)
        {
            System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
            byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(Input);
            byte[] hash = md5.ComputeHash(inputBytes);

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < hash.Length; i++)
            {
                sb.Append(hash[i].ToString("x2"));
            }
            return sb.ToString();
        }

        private static void Boot()
        {
            try
            {
                Console.Title = "[Booting]: WarRock Reloaded Emulator - Game Server";
                Console.WindowHeight = Console.LargestWindowHeight - 25;
                Console.WindowWidth = Console.LargestWindowWidth - 25;

                Log.WriteBlank();
                Log.WritePlain("WarRock Emulator");
                Log.WriteBlank();
                Log.WritePlain("    Rev Info:");
                Log.WritePlain("        Chapter 3");
                Log.WriteBlank();
                Log.WritePlain("    Credits:");
                Log.WritePlain("        TweekSoft");
                Log.WritePlain("             NeNo");
                Log.WriteBlank();
                Log.WriteBlank();

                DateTime current = DateTime.Now;
                string nTime = String.Format("{0:dd_MM_yy}", current);

                Log.setup("Log_" + nTime +".txt");

                Log.WriteBlank();

                string settingsFile = IO.workingDirectory + @"/gsettings.ini";
                if (System.IO.File.Exists(settingsFile) == false)
                {
                    Log.WriteError("gsettings.ini not found at " + settingsFile);
                    return;
                }

                Config.SERVER_KEY_PASSWORD = IO.readINI("Server", "key", settingsFile);
                Config.SERVER_NAME = IO.readINI("Server", "name", settingsFile);
                Config.SERVER_IP = IO.readINI("Server", "ip", settingsFile);
                Config.Debug = int.Parse(IO.readINI("Server", "debug", settingsFile));
                if(int.Parse(IO.readINI("Server", "esl", settingsFile)) == 1)
                    ESL = true;
                //Config.ClientVersion = int.Parse(IO.readINI("Server", "clientver", settingsFile));

                Config.Rates = int.Parse(IO.readINI("Server", "Rates", settingsFile));
                LevelCalculator.SetRates(Config.Rates);

                string Host = IO.readINI("Database", "host", settingsFile);
                int Port = int.Parse(IO.readINI("Database", "port", settingsFile));
                string Username = IO.readINI("Database", "username", settingsFile);
                string Password = IO.readINI("Database", "password", settingsFile);
                string Database = IO.readINI("Database", "database", settingsFile);

                if (DB.openConnection(Host, Port, Database, Username, Password) == false)
                {
                    Console.ReadKey();
                    return;
                }

                Username = Password = string.Empty;

                DB.runQuery("UPDATE users SET online='0'");

                Log.WriteBlank();

                PacketManager.setup();
                Program.StartUp();

                _ServerThread = new Thread(new ThreadStart(serverLoop));
                _ServerThread.Priority = ThreadPriority.BelowNormal;
                _ServerThread.Start();

                _CommandThread = new Thread(new ThreadStart(commandLoop));
                _CommandThread.Priority = ThreadPriority.BelowNormal;
                _CommandThread.Start();
            }
            catch (Exception ex)
            {
                Log.WriteError(ex.Message);
            }
        }

        public static void CheckCouponLoop()
        {
            try
            {
                while (true)
                {
                    DateTime current = DateTime.Now;
                    long StartTime = long.Parse(String.Format("{0:yyMMdd}", current));
                    if (Program.BootTime < StartTime)
                    {
                        Program.BootTime = Convert.ToInt32(StartTime);
                        foreach (virtualUser Players in UserManager.getAllUsers())
                        {
                            Players.TodayCoupon = 0;
                            DB.runQuery("UPDATE users SET todaycoupon='0'");
                            DB.runQuery("DELETE FROM users_events WHERE eventid='5'");
                        }
                    }
                    Thread.Sleep(60000);
                }
            }
            catch (Exception ex)
            {
                Log.WriteError(ex.Message);
            }
        }

        public static void Event()
        {
            while (true)
            {
                try
                {
                    if (EventTime == -1)
                    {
                        isEvent = false;
                        EventTime = -1;
                        EXPEvent = 1;
                        DinarEvent = 1;
                    }
                    else
                    {
                        EventTime -= 10;
                    }
                    foreach (virtualUser Players in UserManager.getAllUsers())
                    {
                        Players.send(new PACKET_PING(Players));
                    }
                }
                catch { }
                Thread.Sleep(10000);
            }
        }

        private static void serverLoop()
        {
            try
            {
                while (!_Running) { Thread.Sleep(100); }

                while (_Running)
                {
                    TimeSpan _StartTime = DateTime.Now - System.Diagnostics.Process.GetCurrentProcess().StartTime;
                    Console.Title = "[RUNNING]: WarRock Reloaded Emulator - Game Server | Ram usage: " + (GC.GetTotalMemory(false) / 1024) +" KB" + " | " + UserManager.UserCount + " online players (Running since: " + _StartTime.Days + " days, " + _StartTime.Hours + " hours, " + _StartTime.Minutes + ", minutes!)";
                    Thread.Sleep(2000);
                }
            }
            catch (Exception ex)
            {
                Log.WriteError(ex.Message);
            }
        }

        public static void shutDown()
        {
            if (!_Running) return;

            try
            {
                for (int I = 1; I <= 3; I++)
                {
                    foreach (Virtual_Objects.Room.virtualRoom _Room in RoomManager.getRoomsInChannel(I))
                    {
                        if (_Room == null) continue;
                        _Room.endGame();
                    }
                }
            }
            catch { }

            Thread.Sleep(5000);

            try
            {
                foreach (Virtual_Objects.User.virtualUser _User in UserManager.getAllUsers())
                {
                    if (_User == null) continue;
                    _User.disconnect();
                }
            }
            catch { }

            Environment.Exit(0);

            _Running = false;

            try {
                if (_ServerThread.IsAlive)
                    _ServerThread.Abort();
            }
            catch { }

            try
            {
                if (_CommandThread.IsAlive)
                    _CommandThread.Abort();
            }
            catch { }

            NetworkSocket.CloseSocket();
            DB.runQuery("UPDATE users SET online='0'");
            Environment.Exit(0);
        }

        private static void commandLoop()
        {
            try
            {
                while (_Running)
                {
                    string Command = Console.ReadLine();
                    string[] args = Command.Split(' ');
                    switch (args[0].ToLower())
                    {
                        case "notice":
                            {
                                foreach (Virtual_Objects.User.virtualUser Client in UserManager.getAllUsers())
                                {
                                    Client.send(new PACKET_CHAT("Notice", PACKET_CHAT.ChatType.Notice1, Command.Substring(7), 100, "Notice"));
                                }

                                break;
                            }
                        case "kick":
                            {
                                foreach (Virtual_Objects.User.virtualUser Client in UserManager.getAllUsers())
                                {
                                    if (Client == null) continue;

                                    if (Client.Nickname.ToLower().Equals(args[1].ToLower()) || Client.Username.ToLower().Equals(args[1].ToLower()))
                                    {
                                        Client.disconnect();
                                        Log.WriteLine("User " + Client.Nickname + " is kicked from the server!");
                                        break;
                                    }
                                }
                                Log.WriteError("User " + args[1] + " is not online or doesn't exist!");
                                break;
                            }
                        case "stop":
                            {
                                shutDown();
                                break;
                            }
                    }
                }
            }
            catch { }
        }

        public static void StartUp()
        {
            if (_Running) return;
            _Running = true;
            DateTime Start = DateTime.Now;
            Log.WriteLine("Starting up Emulator on machine " + Environment.MachineName);

            Log.WriteBlank();

            if (ItemManager.Load() == false)
            {
                return;
            }
            
			// Delete in old files
			// Loaded Damage for 352 Weapons!
            WeaponManager.Items = WeaponManager.LoadItems("items.bin");

            Log.WriteBlank();

            ClanManager.Load();
            BanManager.load();
            RankManager.load();
            UserManager.setup();
            RoomManager.setup();
            EventManager.Load();
            NoticeManager.load();
            MapVehicleSeats.Load();
            MapVehicles.Load();
            Thread EventThread = new Thread(Event);
            EventThread.Priority = ThreadPriority.AboveNormal;
            EventThread.Start();
            Thread CouponCheckThread = new Thread(CheckCouponLoop);
            CouponCheckThread.Priority = ThreadPriority.AboveNormal;
            CouponCheckThread.Start();
            MapManager.load();

            DateTime current = DateTime.Now;
            long StartTime = long.Parse(String.Format("{0:yyMMdd}", current));

            BootTime = int.Parse(StartTime.ToString());

            Log.WriteBlank();

            if (NetworkSocket.openSocket(5340, 2000) == false)
            {
                return;
            }

            TimeSpan bootTime = DateTime.Now - Start;
            Log.WriteLine("Emulator has booted in " + bootTime.TotalMilliseconds + " milliseconds..");

            GC.Collect();
        }

        public static long currTimeStamp
        {
            get
            {
                TimeSpan ts = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0));
                return Convert.ToInt64(ts.TotalSeconds);
            }
        }
        
    }
}
